#ifndef JATOMIC_H
#define JATOMIC_H

#include "jthreadpool_global.h"

// - class JBasicAtomicInt -

/**
 *
 */
class JBasicAtomicIntPrivate;

/**
 * @brief The JBasicAtomicInt class
 */
class JTHREADPOOL_EXPORT JBasicAtomicInt
{
public:
    /**
     * @brief JBasicAtomicInt
     */
    JBasicAtomicInt();

    /**
     * @brief JBasicAtomicInt
     * @param value
     */
    explicit JBasicAtomicInt(int value);
    ~JBasicAtomicInt();

    // Non-atomic API

    /**
     * @brief operator ==
     * @param value
     * @return
     */
    bool operator==(int value) const;

    /**
     * @brief operator !=
     * @param value
     * @return
     */
    bool operator!=(int value) const;

    /**
     * @brief operator !
     * @return
     */
    bool operator!() const;

    /**
     * @brief operator int
     */
    operator int() const;

    /**
     * @brief value
     * @return
     */
    int value() const;

    /**
     * @brief setValue
     * @param value
     */
    void setValue(int value);

    // Atomic API

    /**
     * @brief isReferenceCountingNative
     * @return
     */
    static bool isReferenceCountingNative();

    /**
     * @brief isReferenceCountingWaitFree
     * @return
     */
    static bool isReferenceCountingWaitFree();

    /**
     * @brief ref
     * @return
     */
    bool ref();

    /**
     * @brief deref
     * @return
     */
    bool deref();

    /**
     * @brief isTestAndSetNative
     * @return
     */
    static bool isTestAndSetNative();

    /**
     * @brief isTestAndSetWaitFree
     * @return
     */
    static bool isTestAndSetWaitFree();

    /**
     * @brief testAndSetRelaxed
     * @param expectedValue
     * @param newValue
     * @return
     */
    bool testAndSetRelaxed(int expectedValue, int newValue);

    /**
     * @brief testAndSetAcquire
     * @param expectedValue
     * @param newValue
     * @return
     */
    bool testAndSetAcquire(int expectedValue, int newValue);

    /**
     * @brief testAndSetRelease
     * @param expectedValue
     * @param newValue
     * @return
     */
    bool testAndSetRelease(int expectedValue, int newValue);

    /**
     * @brief testAndSetOrdered
     * @param expectedValue
     * @param newValue
     * @return
     */
    bool testAndSetOrdered(int expectedValue, int newValue);

    /**
     * @brief isFetchAndStoreNative
     * @return
     */
    static bool isFetchAndStoreNative();

    /**
     * @brief isFetchAndStoreWaitFree
     * @return
     */
    static bool isFetchAndStoreWaitFree();

    /**
     * @brief fetchAndStoreRelaxed
     * @param newValue
     * @return
     */
    int fetchAndStoreRelaxed(int newValue);

    /**
     * @brief fetchAndStoreAcquire
     * @param newValue
     * @return
     */
    int fetchAndStoreAcquire(int newValue);

    /**
     * @brief fetchAndStoreRelease
     * @param newValue
     * @return
     */
    int fetchAndStoreRelease(int newValue);

    /**
     * @brief fetchAndStoreOrdered
     * @param newValue
     * @return
     */
    int fetchAndStoreOrdered(int newValue);

    /**
     * @brief isFetchAndAddNative
     * @return
     */
    static bool isFetchAndAddNative();

    /**
     * @brief isFetchAndAddWaitFree
     * @return
     */
    static bool isFetchAndAddWaitFree();

    /**
     * @brief fetchAndAddRelaxed
     * @param valueToAdd
     * @return
     */
    int fetchAndAddRelaxed(int valueToAdd);

    /**
     * @brief fetchAndAddAcquire
     * @param valueToAdd
     * @return
     */
    int fetchAndAddAcquire(int valueToAdd);

    /**
     * @brief fetchAndAddRelease
     * @param valueToAdd
     * @return
     */
    int fetchAndAddRelease(int valueToAdd);

    /**
     * @brief fetchAndAddOrdered
     * @param valueToAdd
     * @return
     */
    int fetchAndAddOrdered(int valueToAdd);

private:
    JBasicAtomicIntPrivate *d;
};

// - class JAtomicInt -

class JAtomicIntPrivate;

/**
 * @brief The JAtomicInt class
 */
class JTHREADPOOL_EXPORT JAtomicInt
{
public:
    /**
     * @brief JAtomicInt
     * @param value
     */
    JAtomicInt(int value = 0);
    ~JAtomicInt();

    /**
     * @brief JAtomicInt
     * @param other
     */
    JAtomicInt(const JAtomicInt &other);

    /**
     * @brief operator =
     * @param value
     * @return
     */
    JAtomicInt &operator =(int value);

    /**
     * @brief operator =
     * @param other
     * @return
     */
    JAtomicInt &operator =(const JAtomicInt &other);

    /**
     * @brief operator ==
     * @param value
     * @return
     */
    bool operator ==(int value) const;

    /**
     * @brief operator !=
     * @param value
     * @return
     */
    bool operator !=(int value) const;

    /**
     * @brief operator !
     * @return
     */
    bool operator !() const;

    /**
     * @brief operator int
     */
    operator int() const;

    // Atomic API

    /**
     * @brief isReferenceCountingNative
     * @return
     */
    static bool isReferenceCountingNative();

    /**
     * @brief isReferenceCountingWaitFree
     * @return
     */
    static bool isReferenceCountingWaitFree();

    /**
     * @brief ref
     * @return
     */
    bool ref();

    /**
     * @brief deref
     * @return
     */
    bool deref();

    /**
     * @brief isTestAndSetNative
     * @return
     */
    static bool isTestAndSetNative();

    /**
     * @brief isTestAndSetWaitFree
     * @return
     */
    static bool isTestAndSetWaitFree();

    /**
     * @brief testAndSetRelaxed
     * @param expectedValue
     * @param newValue
     * @return
     */
    bool testAndSetRelaxed(int expectedValue, int newValue);

    /**
     * @brief testAndSetAcquire
     * @param expectedValue
     * @param newValue
     * @return
     */
    bool testAndSetAcquire(int expectedValue, int newValue);

    /**
     * @brief testAndSetRelease
     * @param expectedValue
     * @param newValue
     * @return
     */
    bool testAndSetRelease(int expectedValue, int newValue);

    /**
     * @brief testAndSetOrdered
     * @param expectedValue
     * @param newValue
     * @return
     */
    bool testAndSetOrdered(int expectedValue, int newValue);

    /**
     * @brief isFetchAndStoreNative
     * @return
     */
    static bool isFetchAndStoreNative();

    /**
     * @brief isFetchAndStoreWaitFree
     * @return
     */
    static bool isFetchAndStoreWaitFree();

    /**
     * @brief fetchAndStoreRelaxed
     * @param newValue
     * @return
     */
    int fetchAndStoreRelaxed(int newValue);

    /**
     * @brief fetchAndStoreAcquire
     * @param newValue
     * @return
     */
    int fetchAndStoreAcquire(int newValue);

    /**
     * @brief fetchAndStoreRelease
     * @param newValue
     * @return
     */
    int fetchAndStoreRelease(int newValue);

    /**
     * @brief fetchAndStoreOrdered
     * @param newValue
     * @return
     */
    int fetchAndStoreOrdered(int newValue);

    /**
     * @brief isFetchAndAddNative
     * @return
     */
    static bool isFetchAndAddNative();

    /**
     * @brief isFetchAndAddWaitFree
     * @return
     */
    static bool isFetchAndAddWaitFree();

    /**
     * @brief fetchAndAddRelaxed
     * @param valueToAdd
     * @return
     */
    int fetchAndAddRelaxed(int valueToAdd);

    /**
     * @brief fetchAndAddAcquire
     * @param valueToAdd
     * @return
     */
    int fetchAndAddAcquire(int valueToAdd);

    /**
     * @brief fetchAndAddRelease
     * @param valueToAdd
     * @return
     */
    int fetchAndAddRelease(int valueToAdd);

    /**
     * @brief fetchAndAddOrdered
     * @param valueToAdd
     * @return
     */
    int fetchAndAddOrdered(int valueToAdd);

private:
    JAtomicIntPrivate *d;
};

#endif // JATOMIC_H
